package com.gict.antifraudback.interceptor;

import com.gict.antifraudback.config.UnifiedMessageSource;
import com.gict.antifraudback.exception.BusinessException;
import com.gict.antifraudback.exception.MyException;
import com.gict.antifraudback.result.ResultEnum;
import com.gict.antifraudback.result.ResultView;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

/**
 * @Description: Controller异常捕获类
 **/
@RestControllerAdvice
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    private UnifiedMessageSource unifiedMessageSource;

    /**
     * 获取国际化消息
     *
     * @param e 异常
     * @return
     */
    public String getMessage(MyException e) {
        String code = "response." + e.getResponseEnum().toString();
        String message = unifiedMessageSource.getMessage(code, e.getArgs());

        if (message == null || message.isEmpty()) {
            return e.getMessage();
        }

        return message;
    }

    /**
     * 业务异常
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResultView handleBusinessException(MyException e) {
        log.error("handleBusinessException:", e.getMessage(), e);

        return ResultView.error(e.getResultEnum().getCode(), getMessage(e));
    }

    /**
     * 参数校验异常，将校验失败的所有异常组合成一条错误信息
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResultView handleValidException(MethodArgumentNotValidException e) {
        log.error("handleValidException:参数绑定校验异常", e);

        return wrapperBindingResult(e.getBindingResult());
    }

    @ExceptionHandler(MyException.class)
    @ResponseBody
    public ResultView defaultErrorHandler(MyException e) {
        log.error("MyException:{}", e.getMessage());
        return ResultView.error(e.getResultEnum(), e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResultView defaultErrorHandler(Exception e) {
        log.error("MyException:{}", e.getMessage());
        return ResultView.error(ResultEnum.CODE_500, e.getMessage());
    }

    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public ResultView defaultErrorHandler(RuntimeException e) {
        log.error("RuntimeException:", e);
        return ResultView.error(ResultEnum.CODE_500);
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public ResultView defaultErrorHandler(MethodArgumentTypeMismatchException e) {
        log.error("MethodArgumentTypeMismatchException:", e);
        String msg = String.format("参数%s的类型需为%s,您输入的是: %s", e.getName(), e.getRequiredType().getSimpleName(),
                e.getValue());
        return ResultView.error(ResultEnum.CODE_2, msg);
    }

    /**
     * 参数绑定异常
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = BindException.class)
    public ResultView handleBindException(BindException e) {
        log.error("handleBindException:参数绑定校验异常", e);

        return wrapperBindingResult(e.getBindingResult());
    }

    /**
     * 包装绑定异常结果
     *
     * @param bindingResult 绑定结果
     * @return 异常结果
     */
    private ResultView wrapperBindingResult(BindingResult bindingResult) {
        StringBuilder msg = new StringBuilder();

        for (ObjectError error : bindingResult.getAllErrors()) {
            msg.append(", ");
            if (error instanceof FieldError) {
                msg.append(((FieldError) error).getField()).append(": ");
            }
            msg.append(error.getDefaultMessage() == null ? "" : error.getDefaultMessage());

        }

        return ResultView.error(ResultEnum.CODE_2, msg.substring(2));
    }
}
